home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / sound / audiocodec / ulawcompressor.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  23.8 KB  |  690 lines

  1. /*
  2.     File:        uLawCompressor.c
  3.  
  4.     Contains:    uLaw Compression Sound Component
  5.  
  6.     Written by:    Jim Reekes
  7.  
  8.     Copyright:    © 1991-1998 by Apple Computer, Inc., all rights reserved.
  9.  
  10. */
  11. #if defined(_MSC_VER) && !defined(__MWERKS__) 
  12. #pragma warning(disable:4229)        // ignore anachronism used: modifiers on data are ignored
  13. #endif
  14.  
  15. #include <MacTypes.h>
  16. #include <Errors.h>
  17. #include <Endian.h>
  18. #include <Components.h>
  19. #include <MacMemory.h>
  20. #include <Resources.h>
  21. #include <Controls.h>
  22. #include <Dialogs.h>
  23. #include <Sound.h>
  24. #include <MoviesFormat.h>
  25.  
  26. #include "uLawCodec.h"
  27.  
  28.  
  29. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  30. //            Constants
  31. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  32.  
  33. #define kInputFormat        k16BitNativeEndianFormat        /* required input format */
  34. #define kOutputFormat        kCodecFormat                    /* only formats we output */
  35.  
  36. #define ZEROTRAP    1                                        /* turn on the trap as per the MIL-STD */
  37.  
  38. enum {
  39.     kOutputSampleSize        = 16,                                /* size of output samples */
  40.     kOutputSamples            = ((kMaxOutputSamples / kULawBlockSamples) * kULawBlockSamples),    /* max actual samples in output buffer */
  41.     kOutputBufferBytes        = ((kMaxOutputSamples / kULawBlockSamples) * kULawBlockBytes * 2),    /* room for ULaw stereo data */
  42.     kLeftoverBufferBytes    = (kULawBlockSamples * 2 * 2),        /* room for leftover stereo 16-bit samples */
  43.  
  44.     kInputSampleSize        = 16,
  45.  
  46.     BIAS                    = 0x84,                            /* define the add-in bias for 16 bit samples */
  47.     CLIP                    = 32635,
  48.  
  49.     kOptionCheckBox            = 4
  50. };
  51.  
  52. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  53. //            types
  54. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  55.  
  56. #if PRAGMA_STRUCT_ALIGN
  57.     #pragma options align=mac68k
  58. #elif PRAGMA_STRUCT_PACKPUSH
  59.     #pragma pack(push, 2)
  60. #elif PRAGMA_STRUCT_PACK
  61.     #pragma pack(2)
  62. #endif
  63.  
  64. // Keep your data long word aligned for best performance
  65.  
  66. typedef struct {
  67.     ComponentInstance        self;                                /* our instance */
  68.     ComponentInstance        sourceComponent;                    /* who to call for more source data */
  69.     SoundComponentDataPtr    sourceDataPtr;                        /* pointer to source data descriptor */
  70.     SoundComponentData        outputData;                            /* local data descriptor record */
  71.     SoundSource                sourceID;
  72.     long                    outputBufferSamples;                /* no. samples in output buffer */
  73.     CompressionInfo            sourceCompInfo;                        /* info about source data format */
  74.     CompressionInfo            destCompInfo;                        /* info about destination data format */
  75.     Handle                    ulawTableHandle;                    /* resource handle to ulaw table */
  76.     Byte                    *ulawTable;                            /* pointer to ulaw table */
  77.     unsigned long            leftOverSamples;                    /* no. samples in leftover buffer */
  78.     Byte                    leftOverBuffer[kLeftoverBufferBytes];                /* space for leftover samples */
  79.     Byte                    buffer[kOutputBufferBytes + kLeftoverBufferBytes];    /* buffer space */
  80. } ULawCompGlobals, *ULawCompGlobalsPtr;
  81.  
  82. typedef struct {
  83.     AudioFormatAtom            formatData;
  84.     AudioEndianAtom            endianData;
  85.     AudioTerminatorAtom        terminatorData;
  86. } AudioCompressionAtom, *AudioCompressionAtomPtr, **AudioCompressionAtomHandle;
  87.  
  88. #if PRAGMA_STRUCT_ALIGN
  89.     #pragma options align=reset
  90. #elif PRAGMA_STRUCT_PACKPUSH
  91.     #pragma pack(pop)
  92. #elif PRAGMA_STRUCT_PACK
  93.     #pragma pack()
  94. #endif
  95.  
  96. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  97. //            Prototypes
  98. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  99.  
  100. static OSErr                DisplayOptionsDialog(ULawCompGlobalsPtr globals);
  101. static void                    SetButtonState(DialogPtr dialog, short item, Boolean state);
  102. static short                GetButtonState(DialogPtr dialog, short item);
  103. static OSErr                GetCompressionParams(ULawCompGlobalsPtr globals, AudioCompressionAtomHandle *params);
  104. static OSErr                SetCompressionParams(ULawCompGlobalsPtr globals, UserDataAtom *atom);
  105. static ComponentResult        PrimeSource(ULawCompGlobalsPtr globals);
  106. static unsigned long        SamplesToBytes(unsigned long sampleCount,  CompressionInfoPtr compInfo);
  107. static unsigned long        BytesToSamples(unsigned long byteCount,  CompressionInfoPtr compInfo);
  108. static unsigned long        SamplesToFrames(unsigned long sampleCount,  CompressionInfoPtr compInfo);
  109. static unsigned long        FramesToSamples(unsigned long framesCount,  CompressionInfoPtr compInfo);
  110. static void                    CompressThisMess(Byte *inputBuffer, Byte *outputBuffer, Byte *ulawTable, long samplesToConvert, short numChannels);
  111. static void                    GetCompressorInfo(CompressionInfoPtr cp);
  112. static void                    CompressULaw(SInt16 *inPtr, Byte *outPtr, Byte *ulawTable, long sampleCount, short numChannels, short whichChannel);
  113.  
  114. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  115. //            Component Dispatcher
  116. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  117.  
  118. #if TARGET_CPU_68K
  119.     #define COMPONENT_C_DISPATCHER
  120.     #define COMPONENT_DISPATCH_MAIN
  121. #endif
  122.  
  123. #define CALLCOMPONENT_BASENAME()         __uLawComp
  124. #define CALLCOMPONENT_GLOBALS()         ULawCompGlobalsPtr storage
  125.  
  126. #define SOUNDCOMPONENT_BASENAME()         CALLCOMPONENT_BASENAME()
  127. #define SOUNDCOMPONENT_GLOBALS()         CALLCOMPONENT_GLOBALS()
  128.  
  129. #define COMPONENT_UPP_SELECT_ROOT()        SoundComponent
  130. #define COMPONENT_DISPATCH_FILE            "uLawCodecDispatch.h"
  131.  
  132. #define    GET_DELEGATE_COMPONENT()        (storage->sourceComponent)
  133.  
  134. #include "Components.k.h"
  135. #include "Sound.k.h"
  136. #include "ComponentDispatchHelper.c"
  137.  
  138.  
  139. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  140. //            Component Routines
  141. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  142.  
  143.  
  144. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  145. static pascal ComponentResult __uLawCompOpen(ULawCompGlobalsPtr globals, ComponentInstance self)
  146. {
  147.     OSErr                result;
  148.  
  149.     globals = (ULawCompGlobalsPtr)NewPtrSysClear(sizeof(ULawCompGlobals));
  150.     FailWithAction(globals == nil, result = MemError(), Failure);
  151.     
  152.     result = GetComponentResource((Component)self, k8BitTableResType, kSoundCompressorResID, &globals->ulawTableHandle);
  153.     FailIf(result != noErr, NoResource);
  154.     
  155.     HLock(globals->ulawTableHandle);
  156.     globals->ulawTable = (Byte *)StripAddress(*globals->ulawTableHandle);
  157.  
  158.     globals->self = self;
  159.     globals->outputData.format = kOutputFormat;            // output format
  160.     globals->outputData.sampleSize = kOutputSampleSize;    // output sample size
  161.  
  162.     globals->outputBufferSamples = kOutputSamples;        // will be set to requested->sampleCount later
  163.  
  164.     // set our storage pointer to our globals
  165.     SetComponentInstanceStorage(self, (Handle) globals);
  166.     return (noErr);
  167.  
  168. NoResource:
  169.     DisposePtr((Ptr)globals);
  170. Failure:
  171.     return (result);
  172. }
  173.  
  174. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  175. static pascal ComponentResult __uLawCompClose(ULawCompGlobalsPtr globals, ComponentInstance self)
  176. {
  177.     ComponentResult        result;
  178.  
  179.     self; // suppress "unused variable" warning for all compilers
  180.  
  181.     if (globals != nil)                                    // we have some globals
  182.     {
  183.         if (globals->sourceComponent)
  184.         {
  185.             result = CloseComponent(globals->sourceComponent);    // torch source component
  186.             FailMessage(result != noErr);
  187.         }
  188.         globals->outputData.sampleCount = 0;            // nothing in our buffer now
  189.  
  190.         if (globals->ulawTableHandle != nil)
  191.             DisposeHandle(globals->ulawTableHandle);
  192.         DisposePtr((Ptr)globals);                        // torch them
  193.     }
  194.  
  195.     return (noErr);
  196. }
  197.  
  198. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  199. pascal ComponentResult __uLawCompVersion(ULawCompGlobalsPtr globals)
  200. {
  201.     globals; // suppress "unused variable" warning for all compilers
  202.  
  203.     return (kSoundCompressorVersion);
  204. }
  205.  
  206. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  207. // Sound Component Methods
  208. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  209.  
  210. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  211. static pascal ComponentResult __uLawCompSetSource(ULawCompGlobalsPtr globals, SoundSource sourceID, ComponentInstance source)
  212. {
  213.     SoundComponentData        sourceData;
  214.     short                    i;
  215.     Byte                    *bPtr;
  216.  
  217.     globals->sourceID = sourceID;
  218.     globals->sourceComponent = source;                    // our food source
  219.     globals->sourceDataPtr = nil;                        // nothing read from source yet
  220.  
  221.     bPtr = (Byte *)&sourceData;                            // zero out struct
  222.     for (i = 0; i < sizeof(SoundComponentData); i++)
  223.         bPtr = 0;
  224.         
  225.     sourceData.format = kInputFormat;                    // our source must give us this format
  226.     sourceData.sampleSize = kInputSampleSize;
  227.     sourceData.sampleCount = globals->outputBufferSamples;
  228.  
  229.     // make sure we can get the source we need
  230.     return (noErr);
  231. }
  232.  
  233. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  234. static pascal ComponentResult __uLawCompSetOutput(ULawCompGlobalsPtr globals, SoundComponentDataPtr requested, SoundComponentDataPtr *actual)
  235. {
  236.     globals->outputBufferSamples = requested->sampleCount;                // no. samples to output
  237.     if (globals->outputBufferSamples > kOutputSamples)                    // too much for our buffer
  238.         globals->outputBufferSamples = kOutputSamples;
  239.  
  240.     // must be one of the output formats we support
  241.     if (requested->format != kOutputFormat)
  242.         goto Failure;
  243.  
  244.     globals->outputData = *requested;
  245.     return (noErr);
  246.  
  247. Failure:
  248.     // here's what we can do
  249.     *actual = &globals->outputData;
  250.     return (paramErr);
  251. }
  252.  
  253. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  254. static pascal ComponentResult __uLawCompGetInfo(ULawCompGlobalsPtr globals, SoundSource sourceID, OSType selector, void *infoPtr)
  255. {
  256.     ComponentResult        result;
  257.  
  258.     result = noErr;
  259.     switch (selector)
  260.     {
  261.         case siCompressionFactor:
  262.             GetCompressorInfo(infoPtr);
  263.             break;
  264.  
  265.         case siCompressionParams:
  266.             result = GetCompressionParams(globals, infoPtr);
  267.             break;
  268.  
  269.         case siOptionsDialog:
  270.             *(short *)infoPtr = true;
  271.             break;
  272.  
  273.         default:
  274.             if (globals->sourceComponent == nil)
  275.                 result = siUnknownInfoType;
  276.             else
  277.                 result = SoundComponentGetInfo(globals->sourceComponent, sourceID, selector, infoPtr);
  278.             break;
  279.     }
  280.     return (result);
  281. }
  282.  
  283. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  284. static pascal ComponentResult __uLawCompSetInfo(ULawCompGlobalsPtr globals, SoundSource sourceID, OSType selector, void *infoPtr)
  285. {
  286.     ComponentResult        result;
  287.  
  288.     result = noErr;
  289.     switch (selector)
  290.     {
  291.         case siOptionsDialog:
  292.             DisplayOptionsDialog(globals);
  293.             break;
  294.  
  295.         case siCompressionParams:
  296.             result = SetCompressionParams(globals, infoPtr);
  297.             break;
  298.  
  299.         default:
  300.             if (globals->sourceComponent == nil)
  301.                 result = siUnknownInfoType;
  302.             else
  303.                 result = SoundComponentSetInfo(globals->sourceComponent, sourceID, selector, infoPtr);
  304.             break;
  305.     }
  306.  
  307.     return (result);
  308. }
  309.  
  310. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  311. static pascal ComponentResult __uLawCompPlaySourceBuffer(ULawCompGlobalsPtr globals, SoundSource sourceID, SoundParamBlockPtr pb, long actions)
  312. {
  313.     globals->sourceDataPtr = nil;                        // no source yet
  314.     globals->outputData.sampleCount = 0;                // our buffer is empty
  315.  
  316.     return (SoundComponentPlaySourceBuffer(globals->sourceComponent, sourceID, pb, actions));
  317. }
  318.  
  319. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  320. static pascal ComponentResult __uLawCompStopSource(ULawCompGlobalsPtr globals, short count, SoundSource *sources)
  321. {
  322.     globals->sourceDataPtr = nil;                        // assume our source is gone
  323.     globals->leftOverSamples = 0;                        // clear anything in leftover buffer
  324.     return (SoundComponentStopSource(globals->sourceComponent, count, sources));
  325. }
  326.  
  327. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  328. static pascal ComponentResult __uLawCompGetSourceData(ULawCompGlobalsPtr globals, SoundComponentDataPtr *resultData)
  329. {
  330.     SoundComponentDataPtr    sourceDataPtr;
  331.     long                    samplesToCopy;
  332.     unsigned long            bytesToCopy, framesToCopy, byteOffset;
  333.     ComponentResult            result = noErr;
  334.  
  335.     if (globals->sourceDataPtr == nil)                            // no source pointer so...
  336.     {
  337.         result = PrimeSource(globals);                            // get data from our source
  338.         FailIf(result != noErr, Failure);
  339.     }
  340.  
  341.     sourceDataPtr = globals->sourceDataPtr;                        // get pointer to source sound component
  342.     if ((sourceDataPtr->format == globals->outputData.format) ||        // input and output are same
  343.         (sourceDataPtr->buffer == nil))                                    // or no source buffer
  344.     {
  345.         globals->sourceDataPtr = nil;                            // get new source next time
  346.         *resultData = sourceDataPtr;                            // pass source on down
  347.         return (noErr);                                            // get out
  348.     }
  349.  
  350.     globals->outputData.buffer = globals->buffer;                // initialize output buffer
  351.     globals->outputData.sampleCount = 0;
  352.  
  353.     while ((sourceDataPtr->sampleCount < kULawBlockSamples)    ||    // we don't have enough source for at least one block
  354.            (globals->leftOverSamples))                            // or we have samples in the leftover buffer
  355.     {
  356.         if (sourceDataPtr->sampleCount == 0)                    // used up all the source
  357.         {
  358.             result = SoundComponentGetSourceData(globals->sourceComponent, &globals->sourceDataPtr);    // get more source
  359.             FailIf(result != noErr, Failure);
  360.             sourceDataPtr = globals->sourceDataPtr;                // get pointer to source sound component
  361.             if (sourceDataPtr->sampleCount == 0)                // still no source samples - all done
  362.                 break;
  363.         }
  364.  
  365.         samplesToCopy = kULawBlockSamples - globals->leftOverSamples; // compute samples needed to fill leftover buffer
  366.         if (sourceDataPtr->sampleCount < samplesToCopy)                // not enough source to fill it, so do what we can
  367.             samplesToCopy = sourceDataPtr->sampleCount;
  368.  
  369.         // copy from source into leftover buffer
  370.         bytesToCopy = SamplesToBytes(samplesToCopy, &globals->sourceCompInfo);
  371.         byteOffset = SamplesToBytes(globals->leftOverSamples, &globals->sourceCompInfo);
  372.         BlockMoveData(sourceDataPtr->buffer, globals->leftOverBuffer + byteOffset, bytesToCopy);
  373.  
  374.         sourceDataPtr->buffer += bytesToCopy;                    // samples removed from source
  375.         sourceDataPtr->sampleCount -= samplesToCopy;
  376.         globals->leftOverSamples += samplesToCopy;                // keep track off samples in leftover buffer
  377.  
  378.         if (globals->leftOverSamples == kULawBlockSamples)        // leftover buffer is full
  379.         {
  380.             CompressThisMess(globals->leftOverBuffer, globals->outputData.buffer, globals->ulawTable, kULawBlockSamples, sourceDataPtr->numChannels);
  381.  
  382.             globals->outputData.buffer += SamplesToBytes(kULawBlockSamples, &globals->destCompInfo);
  383.             globals->outputData.sampleCount += kULawBlockSamples;
  384.             globals->leftOverSamples = 0;
  385.  
  386.             if (globals->outputData.sampleCount == kOutputSamples)    // output buffer is full
  387.                 break;                                            // stop converting
  388.         }
  389.     }
  390.  
  391.     samplesToCopy = kOutputSamples - globals->outputData.sampleCount;    // find amount available in output buffer
  392.     if (samplesToCopy > sourceDataPtr->sampleCount)                        // don't copy more than we have
  393.         samplesToCopy = sourceDataPtr->sampleCount;
  394.  
  395.     framesToCopy = SamplesToFrames(samplesToCopy, &globals->destCompInfo);
  396.  
  397.     if (framesToCopy)                                            // source has some data for us
  398.     {
  399.         samplesToCopy = FramesToSamples(framesToCopy, &globals->destCompInfo);
  400.  
  401.         CompressThisMess(sourceDataPtr->buffer, globals->outputData.buffer, globals->ulawTable, samplesToCopy, sourceDataPtr->numChannels);
  402.  
  403.         sourceDataPtr->buffer += SamplesToBytes(samplesToCopy, &globals->sourceCompInfo);    // update input buffer
  404.         sourceDataPtr->sampleCount -= samplesToCopy;
  405.  
  406.         globals->outputData.buffer += SamplesToBytes(samplesToCopy, &globals->destCompInfo);
  407.         globals->outputData.sampleCount += samplesToCopy;
  408.     }
  409.  
  410.     globals->outputData.buffer = globals->buffer;                // reset to beginning of buffer
  411.     *resultData = &globals->outputData;                            // tell them what we made
  412.     return (noErr);
  413.  
  414. Failure:
  415.     return (result);
  416. }
  417.  
  418. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  419. //        sub routines    _
  420. //                         _|_
  421. //        o        _____|   |_____
  422. //          o o  +______________/
  423. //
  424. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  425.  
  426. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  427. static OSErr DisplayOptionsDialog(ULawCompGlobalsPtr globals)
  428. {
  429.     DialogPtr        dialog;
  430.     short            resFile;
  431.     short            currentResFile;
  432.     short            itemHit;
  433.     OSErr            result;
  434.  
  435.     result = noErr;
  436.     currentResFile = CurResFile();
  437.     resFile = OpenComponentResFile((Component)globals->self);
  438.     FailWithAction(resFile == kResFileNotOpened, result = ResError(), Exit);
  439.  
  440.     dialog = GetNewDialog(kSoundCompressorResID, nil, (WindowPtr)-1);
  441.     FailWithAction(dialog == nil, result = resNotFound, NoDialog);
  442.  
  443.     MacSetPort(dialog);
  444.     SetButtonState(dialog, kOptionCheckBox, true);
  445.     SetDialogDefaultItem(dialog, kStdOkItemIndex);
  446.     SetDialogCancelItem(dialog, kStdCancelItemIndex);
  447.     MacShowWindow(dialog);
  448.  
  449.     do
  450.     {
  451.         ModalDialog(nil, &itemHit);
  452.         switch (itemHit)
  453.         {
  454.             case kOptionCheckBox:
  455.                 if (GetButtonState(dialog, kOptionCheckBox))
  456.                     SetButtonState(dialog, kOptionCheckBox, false);
  457.                 else
  458.                     SetButtonState(dialog, kOptionCheckBox, true);
  459.                 break;
  460.                 
  461.             case kStdOkItemIndex:
  462.                 GetButtonState(dialog, kOptionCheckBox);
  463.                 // accept changes according to values set in dialog
  464.                 break;
  465.         }
  466.     } while ( (itemHit != kStdOkItemIndex) && (itemHit != kStdCancelItemIndex) );
  467.  
  468.     DisposeDialog(dialog);
  469.  
  470. NoDialog:
  471.     CloseResFile(resFile);
  472. Exit:
  473.     UseResFile(currentResFile);
  474.     return (result);
  475. }
  476.  
  477. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  478. static void SetButtonState(DialogPtr dialog, short item, Boolean state)
  479. {
  480.     short        iType;
  481.     Handle        iHandle;
  482.     Rect        iRect;
  483.  
  484.     GetDialogItem(dialog, item, &iType, &iHandle, &iRect);
  485.     if (iHandle != nil)
  486.         SetControlValue((ControlHandle) iHandle, (state) ? kControlRadioButtonCheckedValue : kControlRadioButtonUncheckedValue);
  487. }
  488.  
  489. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  490. static short GetButtonState(DialogPtr dialog, short item)
  491. {
  492.     short        iType;
  493.     Handle        iHandle;
  494.     Rect        iRect;
  495.  
  496.     GetDialogItem(dialog, item, &iType, &iHandle, &iRect);
  497.     return (GetControlValue((ControlHandle) iHandle));
  498. }
  499.  
  500. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  501. static OSErr GetCompressionParams(ULawCompGlobalsPtr globals, AudioCompressionAtomHandle *params)
  502. {
  503.     AudioCompressionAtomHandle        atom;
  504.     AudioCompressionAtomPtr            atomPtr;
  505.     OSErr                            result;
  506.  
  507.     globals; // suppress "unused variable" warning for all compilers
  508.  
  509.     result = noErr;
  510.     atom = (AudioCompressionAtomHandle)NewHandle(sizeof(AudioCompressionAtom));
  511.     FailWithAction(atom == nil, result = MemError(), Exit);
  512.  
  513.     atomPtr = *atom;
  514.     atomPtr->formatData.size = EndianU32_NtoB(sizeof(AudioFormatAtom));
  515.     atomPtr->formatData.atomType = EndianU32_NtoB(kAudioFormatAtomType);
  516.     atomPtr->formatData.format = EndianU32_NtoB(kOutputFormat);
  517.  
  518.     atomPtr->endianData.size = EndianU32_NtoB(sizeof(AudioEndianAtom));
  519.     atomPtr->endianData.atomType = EndianU32_NtoB(kAudioEndianAtomType);
  520.     atomPtr->endianData.littleEndian = EndianU16_NtoB(false);        // µlaw is not little endian
  521.  
  522.     atomPtr->terminatorData.size = EndianU32_NtoB(sizeof(AudioTerminatorAtom));
  523.     atomPtr->terminatorData.atomType = EndianU32_NtoB(kAudioTerminatorAtomType);
  524.  
  525.     *params = atom;
  526.  
  527. Exit:
  528.     return (result);
  529. }
  530.  
  531. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  532. static OSErr SetCompressionParams(ULawCompGlobalsPtr globals, UserDataAtom *atom)
  533. {
  534.     OSErr            result;
  535.     short            littleEndian;
  536.     Boolean            moreAtoms;
  537.  
  538.     globals; // suppress "unused variable" warning for all compilers
  539.  
  540.     result = noErr;
  541.     moreAtoms = true;
  542.     littleEndian = false;
  543.     do
  544.     {
  545.         long atomSize = EndianS32_BtoN(atom->size);
  546.         FailWithAction(atomSize < 8, result = invalidAtomErr, Exit);
  547.         switch (EndianU32_BtoN(atom->atomType))
  548.         {
  549.             case kAudioFormatAtomType:
  550.                 FailWithAction(((AudioFormatAtom *)atom)->format != EndianU32_NtoB(kOutputFormat), result = badFormat, Exit);
  551.                 break;
  552.  
  553.             case kAudioEndianAtomType:
  554.                 littleEndian = EndianU16_BtoN(((AudioEndianAtom *)atom)->littleEndian);
  555.                 break;
  556.  
  557.             case kAudioTerminatorAtomType:
  558.                 moreAtoms = false;
  559.                 break;
  560.  
  561.             default:    // unknown atom type
  562.                 break;
  563.         }
  564.         atom = (UserDataAtom *)((long)atom + atomSize);
  565.     } while (moreAtoms);
  566.     if (littleEndian)
  567.         result = paramErr;                        // we do not do little endian
  568.  
  569. Exit:
  570.     return (result);
  571. }
  572.  
  573. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  574. static ComponentResult PrimeSource(ULawCompGlobalsPtr globals)
  575. {
  576.     ComponentResult            result = noErr;
  577.     SoundComponentDataPtr    sourceDataPtr;
  578.  
  579.     result = SoundComponentGetSourceData(globals->sourceComponent, &globals->sourceDataPtr);
  580.     FailIf(result != noErr, Failure);
  581.     FailWithAction(globals->sourceDataPtr == nil, result = paramErr, Failure);
  582.  
  583.     sourceDataPtr = globals->sourceDataPtr;
  584.     globals->outputData.flags = sourceDataPtr->flags;                // copy flags unchanged
  585.     globals->outputData.sampleRate = sourceDataPtr->sampleRate;        // copy sample rate unchanged
  586.     globals->outputData.numChannels = sourceDataPtr->numChannels;    // copy numchannels unchanged
  587.  
  588.     globals->sourceCompInfo.recordSize = sizeof(CompressionInfo);    // get source compression info
  589.     result = GetCompressionInfo(fixedCompression, sourceDataPtr->format,
  590.                                 sourceDataPtr->numChannels, sourceDataPtr->sampleSize,
  591.                                 &globals->sourceCompInfo);
  592.     FailIf(result != noErr, Failure);
  593.  
  594.     globals->destCompInfo.recordSize = sizeof(CompressionInfo);
  595.     GetCompressorInfo(&globals->destCompInfo);                    // get dest compression info
  596.     globals->destCompInfo.bytesPerFrame = globals->destCompInfo.bytesPerPacket * sourceDataPtr->numChannels;
  597.  
  598. Failure:
  599.     return (result);
  600. }
  601.  
  602. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  603. static unsigned long SamplesToBytes(unsigned long sampleCount, CompressionInfoPtr compInfo)
  604. {
  605.     return ((sampleCount / compInfo->samplesPerPacket) * compInfo->bytesPerFrame);
  606. }
  607.  
  608. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  609. static unsigned long BytesToSamples(unsigned long byteCount, CompressionInfoPtr compInfo)
  610. {
  611.     return ((byteCount / compInfo->bytesPerFrame) * compInfo->samplesPerPacket);
  612. }
  613.  
  614. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  615. static unsigned long SamplesToFrames(unsigned long sampleCount, CompressionInfoPtr compInfo)
  616. {
  617.     return (sampleCount / compInfo->samplesPerPacket);
  618. }
  619.  
  620. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  621. static unsigned long FramesToSamples(unsigned long frameCount, CompressionInfoPtr compInfo)
  622. {
  623.     return (frameCount * compInfo->samplesPerPacket);
  624. }
  625.  
  626. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  627. static void CompressThisMess(Byte *inputBuffer, Byte *outputBuffer, Byte *ulawTable, long samplesToConvert, short numChannels)
  628. {
  629.     if (numChannels == 1)
  630.     {
  631.         CompressULaw((SInt16 *) inputBuffer, outputBuffer, ulawTable, samplesToConvert, 1, 1);
  632.     }
  633.     else
  634.     {
  635.         CompressULaw((SInt16 *) inputBuffer, outputBuffer, ulawTable, samplesToConvert, 2, 1);
  636.         CompressULaw((SInt16 *) inputBuffer, outputBuffer, ulawTable, samplesToConvert, 2, 2);
  637.     }
  638. }
  639.  
  640. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  641. static void GetCompressorInfo(CompressionInfoPtr cp)
  642. {
  643.     if (cp->recordSize > sizeof(CompressionInfo))                // limit amount we return
  644.         cp->recordSize = sizeof(CompressionInfo);
  645.  
  646.     cp->compressionID = fixedCompression;
  647.     cp->format = kOutputFormat;
  648.     cp->samplesPerPacket = kULawBlockSamples;
  649.     cp->bytesPerPacket = kULawBlockBytes;
  650.     cp->bytesPerSample = kULawBytesPerSample;
  651. }
  652.  
  653. //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  654. static void CompressULaw(SInt16 *inPtr, Byte *outPtr, Byte *ulawTable, long sampleCount,
  655.                   short numChannels, short whichChannel)
  656. {
  657.     long            sampnum;
  658.     int                sample, sign, exponent, mantissa;
  659.     unsigned char    ulawbyte;
  660.  
  661.     whichChannel -= 1;
  662.     inPtr += whichChannel;                        /* skip to first sample */
  663.     outPtr += whichChannel;
  664.  
  665.       for (sampnum = 0; sampnum < sampleCount; sampnum++)
  666.       {
  667.         sample = *inPtr;
  668.         inPtr += numChannels;                    /* skip to next sample */
  669.  
  670.         /* Get the sample into sign-magnitude. */
  671.         sign = (sample >> 8) & 0x80;            /* set aside the sign */
  672.         if (sign != 0)
  673.             sample = -sample;                    /* get magnitude */
  674.         if (sample > CLIP)
  675.             sample = CLIP;                        /* clip the magnitude */
  676.  
  677.         /* Convert from 16 bit linear to ulaw. */
  678.         sample = sample + BIAS;
  679.         exponent = ulawTable[(sample >> 7) & 0xFF];
  680.         mantissa = (sample >> (exponent + 3)) & 0x0F;
  681.         ulawbyte = ~(sign | (exponent << 4) | mantissa);
  682. #ifdef ZEROTRAP
  683.         if (ulawbyte == 0)
  684.             ulawbyte = 0x02;                    /* optional CCITT trap */
  685. #endif
  686.         *outPtr = ulawbyte;                        /* output compressed sample */
  687.         outPtr += numChannels;
  688.     }
  689. }
  690.